let _boundaryCheckingState = true //检测数字是否越界
//
export function strip(num: string | number, precision = 15) {
    // toPrecision 数字格式化指定长度
    return +parseFloat(Number(num).toPrecision(precision))
}
// console.log(0.1 + 0.2, strip(0.1 + 0.2))

// 判断小数位数
export function digitLength(num: number) {
    const eSplit = num.toString().split(/[eE]/)
    const len = (eSplit[0].split('.')[1] || '').length - +(eSplit[1] || 0)
    return len > 0 ? len : 0
}

// 去除小数的小数点(小数放大到整数)
export function float2Fixed(num: number) {
    if (num.toString().indexOf('e') === -1) {
        return Number(num.toString().replace('.', ''))
    }
    const dLen = digitLength(num)
    return dLen > 0 ? strip(Number(num) * Math.pow(10, dLen)) : Number(num)
}

// 检测数字是否越界
export function checkBoundary(num: number) {
    if (_boundaryCheckingState) {
        if (num > Number.MAX_SAFE_INTEGER || num < Number.MIN_SAFE_INTEGER) {
            // console.warn(`${num} 超出经度限制，结果可能不正确`)
        }
    }
}

// 数组数字迭代操作
export function iteratorOperation(arr: number[], operation: Function) {
    const [num1, num2, ...others] = arr
    let res = operation(num1, num2)
    others.forEach((num) => {
        res = operation(res, num)
    })
    return res
}

// console.log(iteratorOperation([1, 2, 3, 4, 5, 6], (a, b) => a * b))

// 高精度乘法
export function times(...nums: number[]) {
    if (nums.length > 2) {
        return iteratorOperation(nums, times)
    }
    const [num1, num2] = nums
    const num1Changed = float2Fixed(num1)
    const num2Changed = float2Fixed(num2)
    const baseNum = digitLength(num1) + digitLength(num2) //整数乘
    const leftValue = num1Changed * num2Changed
    checkBoundary(leftValue)
    return leftValue / Math.pow(10, baseNum)
}

// console.log(times(1111111111,1111111111))

// 高精度加法
export function plus(...nums: number[]) {
    if (nums.length > 2) {
        return iteratorOperation(nums, plus)
    }
    const [num1, num2] = nums
    const baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)))
    //转换为整数再计算
    return (times(num1, baseNum) + times(num2, baseNum)) / baseNum
}

// 高精度减法
export function minus(...nums: number[]) {
    if (nums.length > 2) {
        return iteratorOperation(nums, minus)
    }
    const [num1, num2] = nums
    const baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)))
    //转换为整数再计算
    return (times(num1, baseNum) - times(num2, baseNum)) / baseNum
}

// 高精度除法
export function divide(...nums: number[]) {
    if (nums.length > 2) {
        return iteratorOperation(nums, divide)
    }
    const [num1, num2] = nums
    const num1Changed = float2Fixed(num1)
    const num2Changed = float2Fixed(num2)
    checkBoundary(num1Changed)
    checkBoundary(num2Changed)
    return times(
        num1Changed / num2Changed,
        strip(Math.pow(10, digitLength(num2) - digitLength(num1)))
    )
}

// 保留多少位小数四舍五入
export function round(num: number, ratio: number) {
    const base = Math.pow(10, ratio)
    let result = divide(Math.round(Math.abs(times(num, base))), base)
    if (num < 0 && result !== 0) {
        result = times(result, -1)
    }
    return result
}


/** 基础数学公式判断 
 * 包含throw 错误内容
 * 请使用catch捕获
*/
export function checkCalcExpressionValid(string: string) {
    // 剔除空白符W
    string = string.replace(/\s/g, '');
    // 错误情况，空字符串
    if ("" === string) {
        throw '错误情况，空字符串'
    }
    // 错误情况，运算符连续
    if (/[\+\-\*\/]{2,}/.test(string)) {
        throw '错误情况，运算符连续'
    }
    // 空括号
    if (/\(\)/.test(string)) {
        throw '错误情况，空括号'
    }
    // 错误情况，括号不配对 使用出栈入栈方式匹配
    const stack = [];
    for (let i = 0, item; i < string.length; i++) {
        item = string.charAt(i);
        if ('(' === item) {
            stack.push('(');
        } else if (')' === item) {
            if (stack.length > 0) {
                stack.pop();
            } else {
                return false;
            }
        }
    }
    if (0 !== stack.length) {
        throw '错误情况，括号不配对'
    }

    // 错误情况，(后面是运算符
    if (/\([\+\-\*\/]/.test(string)) {
        throw '错误情况，(后面是运算符'
    }

    // 错误情况，)前面是运算符
    if (/[\+\-\*\/]\)/.test(string)) {
        throw '错误情况，)前面是运算符'
    }

    //错误情况，运算符号不能在首末位
    if (/^[\+\-\*\/.]|[\+\-\*\/.]$/.test(string)) {
        throw '错误情况，运算符号不能在首末位'
    }

    return true;
}